package com.example.springbootdemo.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultClock;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * @author hh
 * @date 2022/2/28
 */
public class JwtTokenUtils implements Serializable {

    private static final long serialVersionUID = -3301605591108950415L;

    private static final String SECRET = "secret";
    public static final long EXPIRATION = 7200000L;
    public static final String TOKEN_HEADER = "Authorization";
    private static final Clock CLOCK = DefaultClock.INSTANCE;

    /**
     * 根据用户名生成token
     * @param username 用户名
     * @return String
     */
    public static String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return doGenerateToken(claims, username);
    }

    /**
     * 根据token获取用户名
     * @param token token
     * @return String
     */
    public static String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    private static String doGenerateToken(Map<String, Object> claims, String username) {
        final Date createdDate = CLOCK.now();
        final Date expirationDate = calculateExpirationDate(createdDate);

        return Jwts.builder()
                .setClaims(claims)
                .setSubject(username)
                .setIssuedAt(createdDate)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compressWith(CompressionCodecs.GZIP)
                .compact();
    }

    private static Date calculateExpirationDate(Date createdDate) {
        return new Date(createdDate.getTime() + EXPIRATION);
    }

    public static Boolean validateToken(String token, String username) {
        String user = getUsernameFromToken(token);
        return (user.equals(username) && !isTokenExpired(token));
    }

    public static <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }

    private static Claims getAllClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET)
                .parseClaimsJws(token)
                .getBody();
    }


    private static Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(CLOCK.now());
    }

    public static Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

}